﻿using System;
using System.Collections.Generic;

using mvcForum.Core.Abstractions.Interfaces.DependencyManagement;
using mvcForum.Core.Interfaces.DependencyManagement;

using Ninject;
using Ninject.Modules;
using Ninject.Syntax;

namespace mvcForum.DependencyInjection.Ninject {

	public class DIContainer : IDIContainer {
		private readonly IKernel kernel;

		public DIContainer() {
			this.kernel = new StandardKernel(new INinjectModule[] { });
		}

		#region Binding
		//public void Register<TService, TImplementation>(String named) where TImplementation : TService {
		//    this.kernel.Bind<TService>().To<TImplementation>().Named(named);
		//}

		//public void Register(Type service, Type implementation) {
		//    this.kernel.Bind(service).To(implementation);
		//}

		//public void Register(Type service, Type implementation, String named) {
		//    this.kernel.Bind(service).To(implementation).Named(named);
		//}

		//public void RegisterGeneric(Type service, Type implementation, String named) {
		//    this.kernel.Bind(service).To(implementation).Named(named);
		//}

		//public void RegisterSingleton<TService, TImplementation>(String named) where TImplementation : TService {
		//    this.kernel.Bind<TService>().To<TImplementation>().InSingletonScope().Named(named);
		//}

		//public void RegisterSingleton(Type service, Type implementation) {
		//    this.kernel.Bind(service).To(implementation).InSingletonScope();
		//}

		//public void RegisterSingleton(Type service, Type implementation, String named) {
		//    this.kernel.Bind(service).To(implementation).InSingletonScope().Named(named);
		//}

		//public void RegisterInstance<TService>(TService instance) where TService : class {
		//    this.kernel.Bind<TService>().ToConstant(instance);
		//}

		//public void RegisterInstance<TService>(TService instance, String named) where TService : class {
		//    this.kernel.Bind<TService>().ToConstant(instance).Named(named);
		//}

		//public void RegisterInstance(Type service, Object instance) {
		//    this.kernel.Bind(service).ToConstant(instance);
		//}

		//public void RegisterInstance(Type service, Object instance, String named) {
		//    this.kernel.Bind(service).ToConstant(instance).Named(named);
		//}

		public void Register<TService, TImplementation>() where TImplementation : TService {
			this.kernel.Bind<TService>().To<TImplementation>();
		}

		public void RegisterGeneric(Type service, Type implementation) {
			this.kernel.Bind(service).To(implementation);
		}

		public void RegisterGenericPerRequest(Type service, Type implementation) {
			this.kernel.Bind(service).To(implementation).InRequestScope();
		}

		public void RegisterSingleton<TService>(TService instance) {
			this.kernel.Bind<TService>().ToConstant(instance).InSingletonScope();
		}

		public void RegisterSingleton<TService, TImplementation>() where TImplementation : TService {
			this.kernel.Bind<TService>().To<TImplementation>().InSingletonScope();
		}

		public void RegisterPerRequest<TService, TImplementation>() where TImplementation : TService {
			this.kernel.Bind<TService>().To<TImplementation>().InRequestScope();
		}

		public void RegisterPerRequest<TService, TImplementation>(IDictionary<String, Object> constructorParameters) where TImplementation : TService {
			var binding = (IBindingWithOrOnSyntax<TService>)this.kernel.Bind<TService>().To<TImplementation>().InRequestScope();
			foreach (KeyValuePair<String, Object> pair in constructorParameters) {
				binding = binding.WithConstructorArgument(pair.Key, pair.Value);
			}
		}

		public void Register<TService, TImplementation>(IDictionary<String, Object> constructorParameters) where TImplementation : TService {
			var binding = (IBindingWithOrOnSyntax<TService>)this.kernel.Bind<TService>().To<TImplementation>();
			foreach (KeyValuePair<String, Object> pair in constructorParameters) {
				binding = binding.WithConstructorArgument(pair.Key, pair.Value);
			}
		}
		#endregion

		public void UnRegister<TService>() {
			this.kernel.Unbind<TService>();
		}

		public void Configure() {
			// Let's register the container itself, we might need to to register/unregister services!
			this.Register<IDIContainer, DIContainer>();

			// Set our very own custom DependencyResolver.
			var resolver = new DependencyResolver(this.kernel);

			// Let's Bind the resolver itself.
			this.kernel.Bind<IDependencyResolver>().ToConstant(resolver);
			// We'll tell asp.net mvc to use our resolver!
			System.Web.Mvc.DependencyResolver.SetResolver(resolver);
		}
	}
}